//
//  CDrawerView.m
//  Drawer
//
//  Created by Ji Hu on 12-9-3.
//  Copyright (c) 2012年 爱辅导. All rights reserved.
//

#import "CDrawerView.h"
#import "Drawer.h"

#define P_TYPE_S 1
#define P_TYPE_M 2
#define P_TYPE_E 3


@interface LinePoint : NSObject
@property(nonatomic, assign) CGPoint pos;
@property(nonatomic, assign) float width;
@property(nonatomic,assign) int type;
@end

@implementation LinePoint
@synthesize pos;
@synthesize width;
@synthesize type;
@end

@interface CDrawerView ()

- (void)handleDrawGesture:(UIGestureRecognizer *)gestureRecognizer;
- (void)handleScrollGesture:(UIGestureRecognizer *)gestureRecognizer;
- (float)caculateWidth:(UIGestureRecognizer *)gestureRec;

-(LinePoint*)addDrawPoint:(CGPoint)point width:(float)width type:(int)type;

-(void)drawPointsToContext:(CGContextRef) context withPoints:(NSArray*)points;

-(CGRect)caculateDirty:(LinePoint*)pn anotherPoint:(LinePoint*)pm;

-(NSArray*)createBezierQuadCurve;

@end

@implementation CDrawerView

-(void)dealloc{
    if (_drawPoints) {
        [_drawPoints release];_drawPoints=nil;
    }
    [super dealloc];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        UIPanGestureRecognizer *drawgesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleDrawGesture:)];
        [drawgesture setMaximumNumberOfTouches:1];
        [drawgesture setMinimumNumberOfTouches:1];
        [self addGestureRecognizer:drawgesture];
        [drawgesture release];
        
        UIPanGestureRecognizer *scrollgesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScrollGesture:)];
        [scrollgesture setMinimumNumberOfTouches:2];
        [scrollgesture setMaximumNumberOfTouches:3];
        [self addGestureRecognizer:scrollgesture];
        [scrollgesture release];
        
        _drawPoints = [[NSMutableArray alloc] initWithCapacity:20];
        //        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

-(float)caculateWidth:(UIPanGestureRecognizer *)gestureRec{
    CGPoint velo = [gestureRec velocityInView:self];
    float v = caculate2PowAnd2Sqrt(velo.x, velo.y);
    
    float width = 2000.0 / v;
    return filter(width, 1.0, 2.0);
}

-(LinePoint*)addDrawPoint:(CGPoint)point width:(float)width type:(int)type{
    
    LinePoint *lp = [[LinePoint alloc] init];
    lp.pos=point;
    lp.width=width;
    lp.type=type;
    
    [_drawPoints addObject:lp];
    
    return [lp autorelease];
}

-(CGRect)caculateDirty:(LinePoint *)pn anotherPoint:(LinePoint *)pm{
    
    CGRect dirtyRect;
    
    CGFloat bw = pn.width>pm.width?pn.width:pm.width;
    
    dirtyRect.origin.x = (pn.pos.x<pm.pos.x?pn.pos.x:pm.pos.x) - bw;
    dirtyRect.origin.y = (pn.pos.y<pm.pos.y?pn.pos.y:pm.pos.y) - bw;
    dirtyRect.size.width = fabsf(pn.pos.x-pm.pos.x) + 2*bw;
    dirtyRect.size.height = fabsf(pn.pos.y - pm.pos.y) + 2*bw;
    
    return dirtyRect;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    NSArray *bezierQuadPoints = [self createBezierQuadCurve];
    [self drawPointsToContext:context withPoints:bezierQuadPoints];
    [bezierQuadPoints release];
    
    //    [self drawPointsToContext:context withPoints:_drawPoints];
    
}

#define SEGMENTDISTANCE 2.0f

-(NSArray *)createBezierQuadCurve{
    
    if (_drawPoints.count>2) {
        
        NSMutableArray *bqcPoints = [[NSMutableArray alloc] initWithCapacity:_drawPoints.count*4];
        
        for (unsigned int i = 2; i < [_drawPoints count]; ++i) {
            
            LinePoint *prev2 = [_drawPoints objectAtIndex:i - 2];
            LinePoint *prev1 = [_drawPoints objectAtIndex:i - 1];
            LinePoint *cur = [_drawPoints objectAtIndex:i];
            
            CGPoint start = lastCurveToPoint;
            CGPoint controllpoint = ccpMiddle(prev1.pos, prev2.pos);
            CGPoint curvetopoint = ccpMiddle(prev1.pos, cur.pos);
            lastCurveToPoint = curvetopoint;
            
            float dis1 = caculateDistance(&start, &controllpoint);
            float dis2 = caculateDistance(&controllpoint, &curvetopoint);
            
            int seg = ((dis1+dis2)/SEGMENTDISTANCE);
            float step = 1.0f / seg ;
            float t = 0.0f;
            
            if (prev2.type == P_TYPE_S) {
                [bqcPoints addObject:prev2];
                //                 NSLog(@"\n ** ORI START -P( %f , %f )-",prev2.pos.x,prev2.pos.y);
            }
            
            //             NSLog(@"\n from P2( %f , %f ) P1( %f , %f ) PC ( %f , %f ) ****",prev2.pos.x,prev2.pos.y,prev1.pos.x,prev1.pos.y,cur.pos.x,cur.pos.y);
            
            for (int j = 0 ; j <= seg ; j++) {
                
                LinePoint *mpoint = [[LinePoint alloc] init];
                
                CGPoint newp = ccpAdd(ccpAdd(ccpMult(curvetopoint, t*t), ccpMult(controllpoint, 2*t*(1-t))), ccpMult(start, (1-t)*(1-t)));
                
                mpoint.pos=newp;
                mpoint.width = prev1.width;
                mpoint.type = P_TYPE_M;
                
                [bqcPoints addObject:mpoint];
                //                 NSLog(@"\n ~~ ADD POINT -P( %f , %f )-",mpoint.pos.x,mpoint.pos.y);
                [mpoint release];   
                
                t+=step;
            }
            
            if (cur.type==P_TYPE_E) {
                [bqcPoints addObject:cur];
                //                 NSLog(@"\n ^^ ORI END -P( %f , %f )-",cur.pos.x,cur.pos.y);
            }
            
        }
        
        [_drawPoints removeObjectsInRange:NSMakeRange(0, _drawPoints.count-2)];
        
        return bqcPoints;
    }
    
    return nil;
}

#define ADD_TRAPEZOID(A,B,C,D) CGContextMoveToPoint(context, A.x, A.y);CGContextAddLineToPoint(context, B.x, B.y);CGContextAddLineToPoint(context, C.x, C.y);CGContextAddLineToPoint(context, D.x, D.y);CGContextClosePath(context)

#define ADD_CIRCLE(P,R)  CGContextMoveToPoint(context, P.x, P.y);CGContextAddArc(context, P.x, P.y, R, 0, M_PI*2, 1)

-(void)drawPointsToContext:(CGContextRef)context withPoints:(NSArray *)points{
    
    if (points.count<=0) {
        return;
    }
    
    CGContextBeginPath(context);
    
    LinePoint *preLinePoint = [points objectAtIndex:0];
    
    for (int i = 1 ; i<points.count; i++) {
        
        CGPoint prepos = preLinePoint.pos;
        
        LinePoint *curLinePoint = [points objectAtIndex:i];
        CGPoint curpos = curLinePoint.pos;
        
        NSLog(@"\n draw point to -P( %f , %f )-",curpos.x,curpos.y);
        
        CGPoint dir = CGPointMake(curLinePoint.pos.x - prepos.x, curLinePoint.pos.y - prepos.y);
        CGPoint perpen = cPerpendicularVec(&dir);
        
        CGPoint A = cAdd(&prepos, &perpen, preLinePoint.width);
        CGPoint B = cMin(&prepos, &perpen, preLinePoint.width);
        CGPoint C = cMin(&curpos, &perpen, curLinePoint.width);
        CGPoint D = cAdd(&curpos, &perpen, curLinePoint.width);
        
        if (preLinePoint.type != P_TYPE_S && curLinePoint.type!= P_TYPE_E) {
            A = preD;
            B = preC;
        }
        
        ADD_TRAPEZOID(A, B, C, D);
        
        //add circle at end and start of the line.
        if (preLinePoint.type == P_TYPE_S ) {
            ADD_CIRCLE(prepos, preLinePoint.width);
        }
        if (curLinePoint.type == P_TYPE_E) {
            ADD_CIRCLE(curpos, curLinePoint.width);
        }
        
        //no use now
        preC = C;
        preD = D;
        
        preLinePoint = curLinePoint;
    }
    
    CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextFillPath(context);
    
}

-(void)handleDrawGesture:(UIGestureRecognizer *)gestureRecognizer{
    
    CGPoint point = [gestureRecognizer locationInView:self];
    CGRect dirty;
    
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        
        [_drawPoints removeAllObjects];
        
        float width = [self caculateWidth:gestureRecognizer];
        [self addDrawPoint:point width:width type:P_TYPE_S];
        lastCurveToPoint=point;
        
        NSLog(@"gesture start.");
        
    }else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
        
        LinePoint *pre=nil;
        if (_drawPoints.count>0) {
            pre = [_drawPoints lastObject];
            CGPoint last = [pre pos];
            float dis = caculateDistance(&point, &last);
            if (dis<1.5) {
                return;
            }
            
        }
        
        float width = [self caculateWidth:gestureRecognizer];
        LinePoint *cur = [self addDrawPoint:point width:width type:P_TYPE_M];
        
        if (pre) {
            dirty = [self caculateDirty:pre anotherPoint:cur];
        }
        
    }else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        
        LinePoint *pre= [_drawPoints lastObject];
        
        float width = [self caculateWidth:gestureRecognizer];
        LinePoint *cur = [self addDrawPoint:point width:width type:P_TYPE_E];
        
        if (pre) {
            dirty = [self caculateDirty:pre anotherPoint:cur];
        }
        NSLog(@"gesture end.");
        
    }else {
        NSLog(@"gesture no handle.");
    }
    
    [self setNeedsDisplay];
    //    [self setNeedsDisplayInRect:dirty];
}

-(void)handleScrollGesture:(UIGestureRecognizer *)gestureRecognizer{
    
    [_drawPoints removeAllObjects];
    
    [self setNeedsDisplay];
    NSLog(@"scroll gesture .");}


@end
